/*
 * @Author: 徐建辰
 * @Date: 2022-05-30 10:47:35
 * @LastEditTime: 2022-05-30 10:47 10:27:39
 * @LastEditors: 徐建辰
 * @Description: fetch请求封装
 */
let baseUrl = ''
inital = {
  method: 'GET',
  params: null,
  body: null,
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  credentials: true,
  responseType: 'JSON',
  cache: 'no-cache'
}

// 校验是否为纯粹的对象
function isPlainObject(obj) {
  var proto, Ctor
  if (!obj || typeof obj !== 'object') return false
  proto = Object.getPrototypeOf(obj)
  if (!proto) return true
  Ctor = proto.hasOwnProperty('constructor') && proto.constructor

  return typeof Ctor === 'function' && Ctor === Object //构造函数是Object
}

export default function fetch(url, config) {
  (config == null || typeof config !== 'object') ? config = {} : null //确保config肯定是对象
  if (config.headers && isPlainObject(config.headers)) {
    config.headers = Object.assign({}, inital.headers, config.headers)
  }
  let {
    method,
    params,
    body,
    headers,
    credentials,
    responseType,
    cache
  } = Object.assign({}, inital, config)

  if (typeof url !== 'string') throw new TypeError(` ${url} is not an string!`)
  if (params !== null) {
    if (isPlainObject(params)) {
      params = Qs.stringify(params)
    }
    url += ` ${url.includes('?') ? '&' : '?'}${params} `//拼接
  }

  // 处理请求主体的数据格式{根据headers中的Content-Type处理成为指定的格式}
  if (body != null) {
    if (isPlainObject(body)) {
      let contentType = headers['Content-Type'] || 'application/json'
      if (contentType.includes('urlencoded')) body = Qs.stringify(body)
      if (contentType.includes('json')) body = JSON.stringify(body)
    }
  }
  //include,允许跨域请求当中携带资源凭证,same-origin,允许同源性请求当中携带资源凭证
  credentials = credentials ? 'include' : 'same-origin'
  method = method.toUpperCase()
  responseType = responseType.toUpperCase()
  config = {
    method,
    credentials,
    cache,
    headers
  }
  (/^(POST|PUT|PATCH)$/i).test(method) ? config.body = body : null

  return fetch(url, config).then(function onfulfilled(response) {
    let {status, statusText} = response
    if (status >= 200 && status < 400) {
      // 真正成功获取数据
      let result
      switch (responseType) {
        case 'TEXT':
          result = response.text()
          break
        case 'JSON':
          result = response.json()
          break
        case 'BLOB':
          result = response.blob()
          break
        case 'ARRAYBUFFER':
          result = response.arrayBuffer()
          break
      }
      return result
    }
    // 应该是失败的处理
    return Promise.reject({
      code: 'STATUS ERROR',
      status,
      statusText
    })
  }).catch(function onrejected(reason) {
    // @1:状态码失败
    if (reason && reason.code === 'STATUS ERROR') {
      switch (reason.status) {
        case 401:
          break
      }
    }

    // @2:断网
    if (!navigator.onLine) {
      // ...
    }

    // @3:处理返回数据格式失败
    // ...

    return Promise.reject(reason)
  })
}